﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Text;
using System.Net.Mail;
using System.Net;
using System.Diagnostics;
using System.Web.Configuration;
using System.Configuration;
using Newtonsoft.Json;
using System.Security.Principal;
using CloudStorageLight.SampleWeb.Models;
using CloudStorageLight.Core;
using System.IO.Compression;
using System.Threading;
using CloudStorageLight.Core.Web;

namespace CloudStorageLight.SampleWeb.Controllers
{
    /// <summary>
    /// FilesControllerのヘルパー
    /// </summary>
    [Authorize]
    public class HelperController : Controller
    {
        protected BlobUser GetCurrentUser()
        {
            var user = new BlobUser(System.Web.HttpContext.Current.User);
            return user;
        }

        protected BlobServiceBase CreateBlobService()
        {
            return new BlobService();
        }

        /// <summary>
        /// ZIPでダウンロード
        /// </summary>
        /// <param name="fc"></param>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<ActionResult> DownloadAsZip(FormCollection fc)
        {

            Response.ContentType = "application/octet-stream";
            var strFileName = "downloadfiles.zip";
            Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName);

            using (var outputStream = new PositionWrapperStream(Response.OutputStream))
            using (var zos = new ZipArchive(outputStream, ZipArchiveMode.Create, false))
            {

                using (var svc = CreateBlobService())
                {
                    foreach (var key in fc.AllKeys)
                    {
                        if (!key.StartsWith("file")) continue;
                        var path = fc[key];
                        var entry = zos.CreateEntry(BlobItem.GetFileName(path), CompressionLevel.Fastest);
                        using (var entryStream = entry.Open())
                        {
                            await svc.DownloadFileAsync(GetCurrentUser(), path, entryStream);
                        }
                    }
                }
            }
            Response.SetCookie(new HttpCookie("fileDownload", "true") { Path = "/" });
            return new EmptyResult();
        }

        //http://stackoverflow.com/questions/16585488/writing-to-ziparchive-using-the-httpcontext-outputstream
        class PositionWrapperStream : Stream
        {
            private readonly Stream wrapped;

            private int pos = 0;

            public PositionWrapperStream(Stream wrapped)
            {
                this.wrapped = wrapped;
            }

            public override bool CanSeek { get { return false; } }

            public override bool CanWrite { get { return true; } }

            public override long Position
            {
                get { return pos; }
                set { throw new NotSupportedException(); }
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                pos += count;
                wrapped.Write(buffer, offset, count);
            }

            public override void Flush()
            {
                wrapped.Flush();
            }

            protected override void Dispose(bool disposing)
            {
                wrapped.Dispose();
                base.Dispose(disposing);
            }


            public override bool CanRead
            {
                get { throw new NotImplementedException(); }
            }

            public override long Length
            {
                get { throw new NotImplementedException(); }
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                throw new NotImplementedException();
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotImplementedException();
            }

            public override void SetLength(long value)
            {
                throw new NotImplementedException();
            }
        }

 
        /// <summary>
        /// フォルダリストDropDownList
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ActionResult> DirectoryDropDownList(string id, string name)
        {
            BlobUser user = GetCurrentUser();
            var svc = CreateBlobService();

            try
            {
                var files = await svc.ListFilesAsync(user, id, 0);
                var current = (BlobDirectory)await svc.GetBlobItemAsync(user, id);

                var items = files.OfType<BlobDirectory>().Select(x => new SelectListItem { Text = x.Path, Value = x.Path, Selected = x.Path == id }).ToList();

                for (var dire = current; dire != null; dire = dire.GetParent())
                {
                    if (items.Any(x => x.Value == dire.Path)) continue;
                    items.Insert(0, new SelectListItem { Text = dire.Path, Value = dire.Path, Selected = dire.Path == id });
                }
                ViewData["DropdownListName"] = name;
                return PartialView("_DirectoryDropDownList", items);
            }
            catch (Exception ex)
            {
                return Content(ex.Message);
            }
        }

    
        public async Task<ActionResult> LogView()
        {
            using(var svc = CreateBlobService())
            {
                var logs = await svc.GetLog(null, null);
                if (logs == null) logs = new List<AccessLog>();
                return View(logs.OrderByDescending(x=>x.Date).Take(1000));

            }
        }
    }
}